// Copyright 2017 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the “License”); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/////////////////////////////////////////////////////////
// includes
/////////////////////////////////////////////////////////
#include "mlGradDir.h"
#include "mlShared.h"
#include "math_fns.h"
#include "bar.h"
#include "utils.h"
#include "bench.h"

/////////////////////////////////////////////////////////
// shared globals
/////////////////////////////////////////////////////////

    __attribute__ ((section(".heapsram"))) static const float fv0[900] =  { 0.359744877F, 0.316170543F, 0.452091426F,
    0.590570688F, 0.586605608F, 0.523489F, 0.543290794F, 0.527328074F,
    0.403460801F, 0.340128243F, 0.381245792F, 0.430162311F, 0.370461762F,
    0.386241138F, 0.460635F, 0.397659332F, 0.439033F, 0.49361226F, 0.5713135F,
    0.551353872F, 0.518490434F, 0.595287681F, 0.575706661F, 0.489569575F,
    0.452162802F, 0.354395211F, 0.350517482F, 0.431906879F, 0.469007462F,
    0.422861725F, 0.485689372F, 0.560106874F, 0.610390663F, 0.652361393F,
    0.653856158F, 0.582974F, 0.586330235F, 0.555162728F, 0.45782578F, 0.4364748F,
    0.370872647F, 0.381736338F, 0.482002825F, 0.47906971F, 0.398972303F,
    0.363796562F, 0.455334306F, 0.630435109F, 0.624384105F, 0.573794901F,
    0.52452004F, 0.532823205F, 0.566253245F, 0.418366224F, 0.349609107F,
    0.488572806F, 0.553145885F, 0.520911694F, 0.4965927F, 0.506052852F,
    0.396263123F, 0.41330108F, 0.55020231F, 0.435176253F, 0.389054865F,
    0.52217716F, 0.5677194F, 0.55913204F, 0.453172117F, 0.451571643F,
    0.656952083F, 0.682831705F, 0.544549823F, 0.471098244F, 0.507652342F,
    0.483957887F, 0.454770386F, 0.506471694F, 0.435213953F, 0.478543669F,
    0.619635642F, 0.572257221F, 0.496709168F, 0.494582832F, 0.589038432F,
    0.680636406F, 0.63422817F, 0.529280543F, 0.409155846F, 0.434805572F,
    0.342859298F, 0.363562196F, 0.471913725F, 0.564506829F, 0.647988141F,
    0.596142F, 0.469343901F, 0.47322458F, 0.544500351F, 0.617706597F,
    0.613756597F, 0.52458334F, 0.456200749F, 0.404568434F, 0.521409571F,
    0.363114178F, 0.332937807F, 0.403004974F, 0.513091862F, 0.576681912F,
    0.53103292F, 0.495874256F, 0.489585876F, 0.535522163F, 0.576668F,
    0.509309173F, 0.436213583F, 0.37497282F, 0.361125112F, 0.560448289F,
    0.54013741F, 0.412295043F, 0.378181398F, 0.443167955F, 0.496370703F,
    0.588582695F, 0.685308337F, 0.566321492F, 0.490579218F, 0.517662585F,
    0.359675735F, 0.329475611F, 0.426886559F, 0.394490182F, 0.451499969F,
    0.514234543F, 0.45206666F, 0.391433F, 0.420451313F, 0.463171571F,
    0.518679261F, 0.592543304F, 0.493731707F, 0.402859479F, 0.396873742F,
    0.252072304F, 0.30160287F, 0.510372221F, 0.475035042F, 0.38146171F,
    0.542696834F, 0.511261523F, 0.388022244F, 0.340856284F, 0.344148815F,
    0.340408713F, 0.357130229F, 0.371940315F, 0.32694611F, 0.281907976F,
    0.318291426F, 0.407590896F, 0.479242265F, 0.442820489F, 0.372144639F,
    0.69410032F, 0.543302357F, 0.386832297F, 0.348201215F, 0.332217604F,
    0.361774981F, 0.411175549F, 0.458728701F, 0.383065581F, 0.313602954F,
    0.450667173F, 0.501017928F, 0.466678739F, 0.468793094F, 0.439178973F,
    0.623307228F, 0.392824769F, 0.332589597F, 0.425064027F, 0.414584845F,
    0.481115401F, 0.566573381F, 0.549564362F, 0.494270921F, 0.431558043F,
    0.449673921F, 0.449453086F, 0.468458563F, 0.533500731F, 0.499715835F,
    0.406595886F, 0.267960519F, 0.310223F, 0.451521397F, 0.482406974F,
    0.552146375F, 0.560343F, 0.521590769F, 0.576864481F, 0.561121762F, 0.452559F,
    0.370729625F, 0.473906F, 0.638449669F, 0.578358948F, 0.291010827F,
    0.27395764F, 0.357628703F, 0.420415282F, 0.461061984F, 0.493391424F,
    0.464707464F, 0.521313369F, 0.645002484F, 0.651789427F, 0.544826925F,
    0.439479858F, 0.504653394F, 0.631796896F, 0.599138856F, 0.387533754F,
    0.42593053F, 0.50037843F, 0.510285795F, 0.512783051F, 0.448245466F,
    0.392224818F, 0.500915289F, 0.589378417F, 0.495308071F, 0.412891537F,
    0.3835437F, 0.422032982F, 0.517108381F, 0.544625163F, 0.260647237F,
    0.402410626F, 0.467031419F, 0.400161594F, 0.427229881F, 0.443137378F,
    0.500712335F, 0.624874532F, 0.588067889F, 0.51779443F, 0.48072955F,
    0.407010615F, 0.491150796F, 0.614747584F, 0.666588128F, 0.384458184F,
    0.42278114F, 0.421512395F, 0.411619246F, 0.47268337F, 0.51979506F,
    0.619042218F, 0.687215686F, 0.500303328F, 0.388374478F, 0.45693481F,
    0.450646222F, 0.531617224F, 0.662819266F, 0.653707623F, 0.564806402F,
    0.478809536F, 0.485742301F, 0.470325381F, 0.419771731F, 0.442075849F,
    0.531062245F, 0.625171781F, 0.489674807F, 0.344200164F, 0.503374696F,
    0.618141949F, 0.603444695F, 0.610842824F, 0.4747805F, 0.548001289F,
    0.430320233F, 0.461751819F, 0.386874735F, 0.293353587F, 0.35376969F,
    0.378026754F, 0.487579644F, 0.542309463F, 0.504067719F, 0.620606482F,
    0.612186611F, 0.488864809F, 0.485767573F, 0.382243901F, 0.456170171F,
    0.345480442F, 0.388990402F, 0.336167574F, 0.274184138F, 0.387633532F,
    0.429303765F, 0.444448918F, 0.53201431F, 0.635618269F, 0.622217417F,
    0.40039742F, 0.253895223F, 0.365156323F, 0.46284321F, 0.452746779F,
    0.351559639F, 0.381028175F, 0.414506614F, 0.37999922F, 0.554651082F,
    0.658877552F, 0.489967376F, 0.39318043F, 0.510260165F, 0.529293954F,
    0.38493219F, 0.313968539F, 0.405869126F, 0.532159925F, 0.539621472F,
    0.422823846F, 0.400258809F, 0.490421325F, 0.440943301F, 0.595833719F,
    0.735627592F, 0.570521295F, 0.362343043F, 0.288727969F, 0.34150362F,
    0.433087617F, 0.484554052F, 0.470784783F, 0.471296668F, 0.609254241F,
    0.552945852F, 0.517418206F, 0.512359321F, 0.387771279F, 0.490982831F,
    0.701657414F, 0.702422142F, 0.529085457F, 0.289390326F, 0.231714413F,
    0.350346535F, 0.399430752F, 0.423328102F, 0.4893637F, 0.49889645F,
    0.551650405F, 0.575868905F, 0.445807397F, 0.32951051F, 0.42378509F,
    0.620588541F, 0.666838765F, 0.527969897F, 0.348799616F, 0.345873654F,
    0.461908311F, 0.378150135F, 0.382456154F, 0.584195614F, 0.429232508F,
    0.462356538F, 0.52570051F, 0.447103471F, 0.403240472F, 0.449636072F,
    0.557193279F, 0.571555853F, 0.416364938F, 0.320657462F, 0.411462247F,
    0.533798933F, 0.446866721F, 0.440541267F, 0.644040465F, 0.507865F,
    0.482724786F, 0.582067668F, 0.617696762F, 0.582140326F, 0.562597394F,
    0.611483693F, 0.545117557F, 0.370347232F, 0.327728152F, 0.336033881F,
    0.39252919F, 0.424554706F, 0.45152694F, 0.584523141F, 0.594739795F,
    0.520434618F, 0.596428573F, 0.7032336F, 0.722435653F, 0.651835442F,
    0.577355444F, 0.418991894F, 0.314553976F, 0.367417514F, 0.346257091F,
    0.392335027F, 0.450491697F, 0.446805596F, 0.565853775F, 0.673739374F,
    0.515739262F, 0.497345626F, 0.579967439F, 0.690392911F, 0.690529764F,
    0.565244138F, 0.437136233F, 0.402097136F, 0.445229799F, 0.472152382F,
    0.515307188F, 0.492055655F, 0.5202896F, 0.693238735F, 0.542712152F,
    0.413544625F, 0.413629472F, 0.396175325F, 0.524644911F, 0.674119234F,
    0.64853543F, 0.603159249F, 0.574696839F, 0.524357915F, 0.486010939F,
    0.486768F, 0.475690842F, 0.533829F, 0.681095481F, 0.535413504F, 0.40822956F,
    0.390526056F, 0.52021271F, 0.632131755F, 0.668445647F, 0.629567F,
    0.528164804F, 0.357223F, 0.307404339F, 0.441078454F, 0.556918442F,
    0.574433446F, 0.531363487F, 0.53157711F, 0.643787622F, 0.449894875F,
    0.376948833F, 0.445968777F, 0.542950153F, 0.600818813F, 0.58395493F,
    0.54780376F, 0.446354628F, 0.382106155F, 0.420872599F, 0.471269488F,
    0.526251376F, 0.498357564F, 0.48276177F, 0.638824224F, 0.445541024F,
    0.399493158F, 0.467792809F, 0.567083657F, 0.569420636F, 0.493253231F,
    0.560954034F, 0.582395732F, 0.449949116F, 0.351967871F, 0.380654782F,
    0.493298858F, 0.506598771F, 0.474099636F, 0.648894429F, 0.504460633F,
    0.451572508F, 0.505336344F, 0.552991152F, 0.467147797F, 0.392491728F,
    0.504268587F, 0.603333116F, 0.484285384F, 0.351284593F, 0.485770732F,
    0.606809497F, 0.471308321F, 0.381851912F, 0.696860313F, 0.650649965F,
    0.564018726F, 0.572602093F, 0.511964262F, 0.388421267F, 0.420612693F,
    0.544337392F, 0.613468111F, 0.5135445F, 0.419156104F, 0.629464746F,
    0.757878125F, 0.502038836F, 0.313995063F, 0.614063859F, 0.663943112F,
    0.597718F, 0.632738888F, 0.619338334F, 0.518154383F, 0.586041927F,
    0.655350387F, 0.564700127F, 0.468317032F, 0.462106436F, 0.628425F,
    0.762523472F, 0.619098902F, 0.44448337F, 0.510606349F, 0.602027F,
    0.591120303F, 0.591780066F, 0.576651871F, 0.495697F, 0.579049945F,
    0.624054193F, 0.478581429F, 0.453143269F, 0.49990055F, 0.568527102F,
    0.679807603F, 0.680399895F, 0.604788959F, 0.475417167F, 0.548576355F,
    0.574481785F, 0.520490468F, 0.398176938F, 0.292077333F, 0.369725F,
    0.468242645F, 0.494569F, 0.534378F, 0.547792614F, 0.58956635F, 0.607960582F,
    0.556282461F, 0.498114467F, 0.430138737F, 0.485922933F, 0.50088197F,
    0.469464123F, 0.384560049F, 0.302891403F, 0.296596795F, 0.353041053F,
    0.542781591F, 0.640562832F, 0.607003748F, 0.660969496F, 0.620061338F,
    0.493043035F, 0.420701176F, 0.412961632F, 0.417013109F, 0.416247964F,
    0.436508805F, 0.454417825F, 0.448475063F, 0.361342102F, 0.329954505F,
    0.573888481F, 0.725768745F, 0.654653907F, 0.686695874F, 0.757433474F,
    0.702428579F, 0.542954564F, 0.428331375F, 0.327530235F, 0.322583407F,
    0.457790375F, 0.510899842F, 0.462320834F, 0.349050313F, 0.289456815F,
    0.468396395F, 0.669226289F, 0.641939878F, 0.617483318F, 0.786409736F,
    0.82366693F, 0.572160363F, 0.448446542F, 0.364625603F, 0.342796117F,
    0.533505797F, 0.521065593F, 0.39012295F, 0.416377813F, 0.41699177F,
    0.382865846F, 0.448921889F, 0.484865248F, 0.466779083F, 0.613859296F,
    0.739086449F, 0.556445539F, 0.443911374F, 0.454755783F, 0.398676813F,
    0.447975188F, 0.3728F, 0.304213256F, 0.497562796F, 0.655603111F,
    0.526831865F, 0.358450234F, 0.355582863F, 0.367672652F, 0.428286046F,
    0.564213932F, 0.525030553F, 0.413329571F, 0.425648332F, 0.390117496F,
    0.333011568F, 0.280846059F, 0.337248206F, 0.51955837F, 0.709326327F,
    0.635843635F, 0.433487594F, 0.368183821F, 0.390945673F, 0.427418381F,
    0.453403205F, 0.474294454F, 0.413358718F, 0.373139173F, 0.444402516F,
    0.44228065F, 0.403119862F, 0.504825354F, 0.5907951F, 0.665511191F,
    0.635258734F, 0.486554772F, 0.38344425F, 0.399358541F, 0.49606964F,
    0.536294699F, 0.537216127F, 0.64487046F, 0.641352475F, 0.628795147F,
    0.620487094F, 0.48733F, 0.398404419F, 0.431141227F, 0.381335467F,
    0.307017475F, 0.321006894F, 0.504081249F, 0.684042394F, 0.688935161F,
    0.737379849F, 0.792049527F, 0.4798567F, 0.498101443F, 0.56377244F,
    0.581159949F, 0.445942312F, 0.33117795F, 0.403949291F, 0.436417639F,
    0.365139484F, 0.331013322F, 0.549681067F, 0.750052F, 0.619392157F,
    0.542932928F, 0.566830039F, 0.444650263F, 0.489180893F, 0.472606659F,
    0.474505633F, 0.40967828F, 0.376853138F, 0.444594055F, 0.430343866F,
    0.437794834F, 0.46720311F, 0.585994184F, 0.68250984F, 0.521382689F,
    0.367880225F, 0.334864646F, 0.422155499F, 0.489864022F, 0.441337228F,
    0.447898775F, 0.455834687F, 0.473367721F, 0.481037915F, 0.367102087F,
    0.428740352F, 0.633817315F, 0.653956831F, 0.562075317F, 0.475049525F,
    0.398689777F, 0.37533623F, 0.357731909F, 0.417444378F, 0.469486713F,
    0.508817315F, 0.583789885F, 0.680687428F, 0.66628474F, 0.483797252F,
    0.437114596F, 0.666926086F, 0.715835452F, 0.519536495F, 0.373639435F,
    0.387119532F, 0.528399765F, 0.470904529F, 0.488215238F, 0.471634418F,
    0.466168523F, 0.553932726F, 0.716451466F, 0.75388515F, 0.648280799F,
    0.508637786F, 0.560147643F, 0.708205283F, 0.618636191F, 0.376283735F,
    0.377265751F, 0.594706F, 0.570489347F, 0.575978637F, 0.466203362F,
    0.417409867F, 0.449630231F, 0.517802715F, 0.602820396F, 0.678178549F,
    0.581961393F, 0.517065465F, 0.694916844F, 0.722516716F, 0.496630579F,
    0.445694953F, 0.603063226F, 0.535671234F, 0.499028295F, 0.418471277F,
    0.426870644F, 0.43418926F, 0.390195459F, 0.449020177F, 0.610477805F,
    0.651351273F, 0.585574031F, 0.660475075F, 0.684935808F, 0.508143663F,
    0.445290476F, 0.533628345F, 0.492427528F, 0.44191578F, 0.382018387F,
    0.413299978F, 0.459958225F, 0.45837158F, 0.436699927F, 0.488234639F,
    0.623891F, 0.621064544F, 0.592755079F, 0.573679149F, 0.53581214F,
    0.537148654F, 0.437466323F, 0.503998637F, 0.497201502F, 0.447905779F,
    0.513876736F, 0.612775147F, 0.626312256F, 0.571840465F, 0.505760431F,
    0.546498239F, 0.577943444F, 0.549296141F, 0.563639581F, 0.648227513F,
    0.637769759F, 0.436736882F, 0.538285494F, 0.505094528F, 0.512460589F,
    0.618744314F, 0.66731149F, 0.653866768F, 0.67052871F, 0.578027606F,
    0.470279217F, 0.450765938F, 0.485201329F, 0.666400254F, 0.695342481F,
    0.517169595F, 0.419412106F, 0.49592483F, 0.434757143F, 0.547457F,
    0.615539074F, 0.514379F, 0.512728095F, 0.616033733F, 0.537951231F,
    0.389630556F, 0.306748539F, 0.371245027F, 0.673655093F, 0.712841213F,
    0.457850873F, 0.355890125F, 0.428222239F, 0.425910085F, 0.577554643F,
    0.55832696F, 0.408150166F, 0.480950147F, 0.629312217F, 0.563351691F,
    0.402880698F, 0.303544551F, 0.340243429F, 0.594868183F, 0.748673797F,
    0.561704516F, 0.345169067F, 0.42556724F, 0.429588616F, 0.48580274F,
    0.485043615F, 0.455412775F, 0.57235F, 0.643402696F, 0.539393842F, 0.44004F,
    0.429496586F, 0.412063539F, 0.504424155F, 0.66131705F, 0.576749086F,
    0.387458235F, 0.39482367F, 0.36750108F, 0.353736848F, 0.425428122F,
    0.530631F, 0.635570467F, 0.614352942F, 0.492482245F, 0.465242207F, 0.512482F,
    0.439176F, 0.397014052F, 0.481915921F, 0.497919738F, 0.420029402F };

    __attribute__ ((section(".heapsram")))   static const float fv1[16] = { 1.21272373F, 1.21269941F, 3.00467062F,
    3.00461054F, 8.6396265F, 8.63945293F, 3.0210104F, 3.02094984F, -13.5348644F,
    -13.5351353F, 3.34801817F, 3.34795141F, 5.83478451F, 5.83466816F, 3.349828F,
    3.34976077F };


/////////////////////////////////////////////////////////
// subfunctions
/////////////////////////////////////////////////////////


void mlGrad(const float img[225], float filt[169])
{
  int x;
  int y;
  float a;
  float b_a;

  /*  mlGrad */
  for (x = 0; x < 13; x++) {
    for (y = 0; y < 13; y++) {
      /*  sobel mask in x-direction */
      a = (((img[y + 15 * (2 + x)] - img[y + 15 * x]) + 2.0F * (img[(y + 15 * (2
               + x)) + 1] - img[(y + 15 * x) + 1])) + img[(y + 15 * (2 + x)) + 2])
        - img[(y + 15 * x) + 2];

      /*  sobel mask in y-direction */
      b_a = (((img[(y + 15 * x) + 2] - img[y + 15 * x]) + 2.0F * (img[(y + 15 *
                (1 + x)) + 2] - img[y + 15 * (1 + x)])) + img[(y + 15 * (2 + x))
             + 2]) - img[y + 15 * (2 + x)];
      
      filt[y + 13 * x] = fAtan2(b_a, a);
    }
  }
}


boolean_T checkRes(const float check[2], const float golden[4], const int coreid)
{
  int k;
  boolean_T pass = true;
  boolean_T flag = true;

  for (k = 0; k < 2; k++) {

    flag = true;
    flag = flag && (check[k] <= golden[k << 1]);
    flag = flag && (check[k] >= golden[1 + (k << 1)]);
    printErrors(!flag, k, check[k] ,golden[k << 1] , golden[1 + (k << 1)]);
    pass = flag && pass;
  }

  return pass;
}


float var(const float x[169])
{
  float y;
  int ix;
  float xbar;
  int k;
  float r;
  ix = 0;
  xbar = x[0];
  for (k = 0; k < 168; k++) {
    ix++;
    xbar += x[ix];
  }

  xbar = fDiv(xbar,169.0F);
  ix = 0;
  r = x[0] - xbar;
  y = r * r;
  for (k = 0; k < 168; k++) {
    ix++;
    r = x[ix] - xbar;
    y += r * r;
  }

  y = fDiv(y,168.0F);
  return y;
}

float sum(const float x[169])
{
  float y;
  int k;
  y = x[0];
  for (k = 0; k < 168; k++) {
    y += x[k + 1];
  }

  return y;
}


/////////////////////////////////////////////////////////
// main testing function 
/////////////////////////////////////////////////////////
int main(int argc, const char * const argv[])
{
  (void)argc;
  (void)argv;

  int coreid, k,j;
  boolean_T pass;
  float y[169];
  float tmp[2];
  
  /////////////////////////////////////////////////////////
  // main test loop 
  // each core loops over a kernel instance
  /////////////////////////////////////////////////////////
  
  coreid = get_core_id();

  printf("starting %d kernel iterations... (coreid = %d)\n",KERNEL_ITS,coreid);
  
  if (coreid>3)
    coreid=coreid-4;

  synch_barrier();

  perf_begin();

  for(k = 0; k < getKernelIts(); k++)
  {
    // matlab kernel
    mlGrad(*(float (*)[225])&fv0[225 * coreid], y);
  }

  synch_barrier();

  perf_end();

  /////////////////////////////////////////////////////////
  // check results
  /////////////////////////////////////////////////////////


  tmp[0] = sum(y);
  tmp[1] = var(y);
  pass   = checkRes(tmp, *(float (*)[4])&fv1[coreid << 2], coreid);
    
  flagPassFail(pass, get_core_id());

  synch_barrier();

/////////////////////////////////////////////////////////
// synchronize and exit
/////////////////////////////////////////////////////////

  return !pass;
}

